package com.cupcorn.balapkarung.entity;

import java.util.ArrayList;

import org.andengine.entity.primitive.Line;
import org.andengine.util.color.Color;

import com.cupcorn.balapkarung.GameDefine;
import com.cupcorn.balapkarung.GameDefineText;
import com.cupcorn.balapkarung.LocalData;
import com.cupcorn.lib.Anchor;
import com.cupcorn.lib.Ratio;
import com.cupcorn.lib.display.DisplayText;
import com.cupcorn.lib.game.GameAnimatedSprite;
import com.cupcorn.lib.game.GameEngine;
import com.cupcorn.lib.game.GameSprite;

public class MC implements GameDefine
{
	public final int			IDLE	= 0, MOVE = 1, JUMP = 2, DOWN = 3, DIE = 4;
	public int					curState;
	public final int			SPEED	= 200, X_JUMP_SPEED = 0, Y_JUMP_SPEED = 600, ACCELERATION = 10, BACK_DISTANCE_DIE = 200, GRAVITATION = 900;
	public float				xSpeed, ySpeed, speed, yJump, timeBack = 0.5f, second, distance;
	public final int			MAX_JUMP	= 2, MAX_HIGH_JUMP = 175;
	public int					curJump;
	public int					xStart, yStart;
	public float				curGravitation;
	public boolean			isInGround;
	int							curIndexJump, curIndexDown;
	public GameAnimatedSprite	mc;
	GameSprite					icon;
	GameEngine					engine;
	public Line					linkedText;
	public DisplayText			displayText;
	boolean						isPlayer;
	public float				xText, xLinked, yLinked, timeAlpha = 2, timeVisible = 2, curTime;
	
	public MC(GameEngine engine, GameAnimatedSprite mc, String name, GameSprite icon)
	{
		this.engine = engine;
		this.mc = mc;
		this.icon = icon;
		xSpeed = SPEED;
		displayText = new DisplayText(engine, engine.displayFont, GameDefineText.MC_NAME);
		displayText.newText(0).setPosition(0, 50, Anchor.TOP_LEFT, Ratio.NONE);
		displayText.text[0].setText(name);
		displayText.text[0].setColor(Color.BLACK);
		displayText.text[0].setAlpha(0);
		xText = (mc.getWidth() - displayText.text[0].getWidth()) / 2;
		if (icon != null)
		{
			isPlayer = true;
			mc.attachChild(icon, 0, -icon.getHeight(), Anchor.TOP_CENTER, Ratio.NONE);
		}
		else
		{
			isPlayer = false;
		}
		linkedText = new Line(0, 0, 0, 0, engine.getVertexBufferObjectManager());
		linkedText.setColor(Color.BLACK);
		linkedText.setAlpha(0);
		xLinked = mc.getWidth() / 2;
		yLinked = displayText.text[0].getY() + displayText.text[0].getHeight();
		engine.scene.attachChild(linkedText);
	}
	
	public void setTextAndLinked(float deltaTime)
	{
		curTime += deltaTime;
		if (curTime < timeAlpha)
		{
			displayText.text[0].setAlpha(displayText.text[0].getAlpha() + 1 / timeAlpha * deltaTime);
			linkedText.setAlpha(linkedText.getAlpha() + 1 / timeAlpha * deltaTime);
		}
		else if (curTime < timeAlpha + timeVisible)
		{
			displayText.text[0].setAlpha(1);
			linkedText.setAlpha(1);
		}
		else if (curTime < timeAlpha * 2 + timeVisible)
		{
			displayText.text[0].setAlpha(displayText.text[0].getAlpha() - 1 / timeAlpha * deltaTime);
			linkedText.setAlpha(linkedText.getAlpha() - 1 / timeAlpha * deltaTime);
		}
		else
		{
			displayText.text[0].setAlpha(0);
			linkedText.setAlpha(0);
		}
		displayText.text[0].setX(mc.getX() + xText);
		if (isPlayer)
			linkedText.setPosition(mc.getX() + xLinked, yLinked, mc.getX() + xLinked, mc.getY() - icon.getHeight());
		else
			linkedText.setPosition(mc.getX() + xLinked, yLinked, mc.getX() + xLinked, mc.getY());
	}
	
	public void switchState(int state)
	{
		curState = state;
		switch (state)
		{
			case IDLE:
				idle();
				break;
			case MOVE:
				move();
				break;
			case JUMP:
				jump();
				break;
			case DOWN:
				down();
				break;
			case DIE:
				die();
				break;
		}
	}
	
	public void onUpdate(float deltaTime)
	{
		switch (curState)
		{
			case IDLE:
				idleUpdate(deltaTime);
				break;
			case MOVE:
				moveUpdate(deltaTime);
				break;
			case DOWN:
			case JUMP:
				jumpUpdate(deltaTime);
				break;
			case DIE:
				dieUpdate(deltaTime);
				break;
		}
	}
	
	private void idle()
	{
		xSpeed = SPEED;
		mc.stopAnimation(0);
	}
	
	private void idleUpdate(float deltaTime)
	{	
		
	}
	
	private void move()
	{
		curJump = 0;
		mc.animate(MC_DUR[LocalData.character_use][ANIM_MOVE], MC_FRAME_2[LocalData.character_use][ANIM_MOVE][0],
			MC_FRAME_2[LocalData.character_use][ANIM_MOVE][1], true);
	}
	
	private void moveUpdate(float deltaTime)
	{
		mc.setPosition(mc.getX() + xSpeed * deltaTime, mc.getY());
		xSpeed += ACCELERATION * deltaTime;
	}
	
	private void jump()
	{
		if (isPlayer) engine.playerSound.play(SOUND_LOMPAT);
		yJump = mc.getY();
		ySpeed = Y_JUMP_SPEED;
		curGravitation = 0;
		curJump++;
		mc.animate(MC_DUR[LocalData.character_use][ANIM_JUMP], MC_FRAME_2[LocalData.character_use][ANIM_JUMP][0],
			MC_FRAME_2[LocalData.character_use][ANIM_JUMP][1], false);
	}
	
	private void jumpUpdate(float deltaTime)
	{
		curGravitation += GRAVITATION * deltaTime;
		mc.setPosition(mc.getX() + xSpeed * deltaTime + X_JUMP_SPEED * deltaTime, mc.getY() + (curGravitation - ySpeed) * deltaTime);
		xSpeed += ACCELERATION * deltaTime;
		if (mc.getY() + MAX_HIGH_JUMP <= yJump)
		{
			yJump = 0;
			switchState(DOWN);
		}
	}
	
	private void down()
	{
		if (curGravitation < ySpeed) curGravitation = ySpeed;
	}
	
	private void die()
	{
		if (isPlayer) engine.playerSound.play(SOUND_MATI);
		mc.stopAnimation(18);
		second = 0;
		distance = mc.getX() - BACK_DISTANCE_DIE;
	}
	
	private void dieUpdate(float deltaTime)
	{
		second += deltaTime;
		xSpeed = (mc.getX() - distance) / timeBack;
		speed = (float) (xSpeed / Math.cos(Math.toRadians(45)));
		ySpeed = (float) (speed * Math.sin(Math.toRadians(45))) - (BACK_DISTANCE_DIE / timeBack * second);
		mc.setPosition(mc.getX() - xSpeed * deltaTime, mc.getY() - ySpeed * deltaTime);
	}
	
	public void startPosition(int x, int y)
	{
		xStart = x;
		yStart = y;
		mc.setPosition(x, y);
	}
	
	public void reset()
	{
		mc.setVisible(true);
		curIndexJump = curIndexDown = 0;
		mc.setPosition(xStart, yStart);
		xSpeed = SPEED;
		switchState(IDLE);
	}
	
	public void replay(int index)
	{
		replay(LocalData.listReplayJump.get(index));
	}
	
	public void replay(ArrayList<Integer> list)
	{
		
		if (list.size() > curIndexJump * 2)
		{
			if (mc.getX() >= list.get(curIndexJump * 2))
			{
				if (curJump == MAX_JUMP)
				{
					curIndexDown++;
				}
				else
				{
					switchState(JUMP);
				}
				curIndexJump++;
			}
		}
		if (list.size() > curIndexDown * 2 + 1)
		{
			if (mc.getX() >= list.get(curIndexDown * 2 + 1))
			{
				switchState(DOWN);
				curIndexDown++;
			}
		}
	}
	
	public void setName(String name)
	{
		displayText.text[0].setText(name);
		xText = (mc.getWidth() - displayText.text[0].getWidth()) / 2;
	}
}